use chrono::{Duration, Utc};
use serde::{Deserialize, Serialize};

use crate::utils;

#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Product {
    pub code: String,
    pub fallback_date: String,
    pub paid_up_to: String,
    pub extended: bool,
}

impl Product {
    pub fn new<S: AsRef<str>>(code: S, authorize_days: i64) -> Self {
        let today = Utc::now().date_naive();
        let expires_date = (today + Duration::days(authorize_days))
            .format("%Y-%m-%d")
            .to_string();
        Self {
            code: code.as_ref().to_string(),
            fallback_date: expires_date.clone(),
            paid_up_to: expires_date,
            extended: true,
        }
    }
}

#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct License {
    pub license_id: String,
    pub licensee_name: String,
    pub assignee_name: String,
    pub assignee_email: String,
    pub license_restriction: String,
    pub check_concurrent_use: bool,
    pub products: Vec<Product>,
    #[serde(rename = "metadata")]
    pub meta_data: String,
    pub hash: String,
    pub grace_period_days: i32,
    pub auto_prolongated: bool,
    pub is_auto_prolongated: bool,
}

impl License {
    pub fn new(
        licensee_name: String,
        assignee_name: String,
        assignee_email: Option<String>,
    ) -> Self {
        Self {
            license_id: utils::generate_license_id(),
            licensee_name,
            assignee_name,
            assignee_email: assignee_email.unwrap_or(String::new()),
            license_restriction: String::new(),
            check_concurrent_use: false,
            products: vec![],
            meta_data: String::from("0120230102PPAA013009"),
            hash: String::from("41472961/0:1563609451"),
            grace_period_days: 7,
            auto_prolongated: true,
            is_auto_prolongated: true,
        }
    }

    pub fn add_product<S: AsRef<str>>(&mut self, product_code: S, valid_days: i64) {
        self.products.push(Product::new(product_code, valid_days));
    }

    pub fn serialize(&self) -> String {
        serde_json::to_string(self).unwrap()
    }
}

#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LicenseRequestForm {
    pub licensee_name: String,
    pub assignee_name: String,
    pub assignee_email: Option<String>,
    pub valid_days: i64,
    pub request_products: Vec<String>,
}
